package com.beiding.codecreater.render.java.boframe.common;

import com.beiding.codecreater.core.render.Template;
import com.beiding.codecreater.core.render.TemplateCompiler;
import com.beiding.codecreater.render.java.common.MyPackage;
import com.beiding.codecreater.render.java.utils.NameUtils;
import com.beiding.codecreater.utils.FileUtils;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

public class Project {

    private String packageRoot;
    private String daoPackage = "dao";
    private String boPackage = "bo";
    private String voPackage = "vo";
    private String bePackage = "entity";

    public Project(String packageRoot) {
        NameUtils.checkPackageName(packageRoot);
        this.packageRoot = packageRoot;
    }

    public String getDaoPackage() {
        return daoPackage;
    }

    public void setDaoPackage(String daoPackage) {
        NameUtils.checkPackageName(daoPackage);
        this.daoPackage = daoPackage;
    }

    public String getBoPackage() {
        return boPackage;
    }

    public void setBoPackage(String boPackage) {
        NameUtils.checkPackageName(boPackage);
        this.boPackage = boPackage;
    }

    public String getVoPackage() {
        return voPackage;
    }

    public void setVoPackage(String voPackage) {
        NameUtils.checkPackageName(voPackage);
        this.voPackage = voPackage;
    }

    public String getBePackage() {
        return bePackage;
    }

    public void setBePackage(String bePackage) {
        NameUtils.checkPackageName(bePackage);
        this.bePackage = bePackage;
    }

    //bo构建map
    private Map<String, BoData> boDataMap = new HashMap<>();

    public BoData getBoDate(String name) {
        return boDataMap.computeIfAbsent(name, k -> {
            BoData boData = new BoData();
            boData.setName(name);
            return boData;
        });
    }

    public BoData removeBoDate(String name) {
        return boDataMap.remove(name);
    }

    //向给定的bo中添加字段
    public void addField(String bo, String type, String name) {
        BoData boDate = getBoDate(bo);
        boDate.setField(type, name);
    }

    public void addField(String bo, String type, String name, Integer length) {
        BoData boDate = getBoDate(bo);
        boDate.setField(type, name, length);
    }

    //TODO 多个引用,删除前校验
    public void addQuote(String holder, String target, String field) {
        BoData h = getBoDate(holder);
        BoData t = getBoDate(target);
        t.addHolder(h, field);
        h.setQuote(t, field);
    }

    public Map<String, BoData> getBoDataMap() {
        return boDataMap;
    }

    public MyPackage getBe(Template template) {
        MyPackage myPackage = new MyPackage(packageRoot + "." + bePackage);
        for (BoData data : boDataMap.values()) {
            new MetaDataClass(data, myPackage, data.getName() + "Be", template);
        }
        return myPackage;
    }

    public MyPackage getBo(Template template) {
        MyPackage myPackage = new MyPackage(packageRoot + "." + boPackage);
        for (BoData data : boDataMap.values()) {
            MetaDataClass metaDataClass = new MetaDataClass(data, myPackage, data.getName(), template);
            metaDataClass.addImport(packageRoot + "." + bePackage + "." + data.getName() + "Be");
            metaDataClass.addImport(packageRoot + "." + voPackage + "." + data.getName() + "Vo");
        }
        return myPackage;
    }

    public MyPackage getTypeSelf(Template template) {
        MyPackage myPackage = new MyPackage(packageRoot + "." + boPackage);
        for (BoData data : boDataMap.values()) {
            new MetaDataClass(data, myPackage, data.getName() + "TypeSelf", template);
        }
        return myPackage;
    }

    public MyPackage getVo(Template template) {
        MyPackage myPackage = new MyPackage(packageRoot + "." + voPackage);
        for (BoData data : boDataMap.values()) {
            MetaDataClass metaDataClass = new MetaDataClass(data, myPackage, data.getName() + "Vo", template);
            metaDataClass.addImport(packageRoot + "." + bePackage + "." + data.getName() + "Be");
        }
        return myPackage;
    }

    public MyPackage getBeDao(Template template) {
        MyPackage myPackage = new MyPackage(packageRoot + "." + daoPackage);
        for (BoData data : boDataMap.values()) {
            MetaDataClass metaDataClass = new MetaDataClass(data, myPackage, data.getName() + "Dao", template);
            metaDataClass.addImport(packageRoot + "." + bePackage + "." + data.getName() + "Be");
        }
        return myPackage;
    }

    public MyPackage getQuoteDao(Template template) {
        MyPackage myPackage = new MyPackage(packageRoot + "." + daoPackage);
        for (BoData data : boDataMap.values()) {
            if (data.getHolders().size() > 0) {
                MetaDataClass metaDataClass = new MetaDataClass(data, myPackage, "_Quote_" + data.getName() + "Dao", template);
                metaDataClass.addImport(packageRoot + "." + bePackage + "._Quote_" + data.getName() + "Be");
            }
        }
        return myPackage;
    }

    public MyPackage getQuote(Template template) {
        MyPackage myPackage = new MyPackage(packageRoot + "." + bePackage);
        for (BoData data : boDataMap.values()) {
            if (data.getHolders().size() > 0) {
                new MetaDataClass(data, myPackage, "_Quote_" + data.getName()+"Be", template);
            }
        }
        return myPackage;
    }
    public MyPackage getBoFactory(Template template) {
        MyPackage myPackage = new MyPackage(packageRoot + "." + boPackage);
        for (BoData data : boDataMap.values()) {
            MetaDataClass metaDataClass = new MetaDataClass(data, myPackage, data.getName() + "Repository", template);
            metaDataClass.addImport(packageRoot + "." + bePackage + "." + data.getName() + "Be");
            metaDataClass.addImport(packageRoot + "." + daoPackage + "." + data.getName() + "Dao");
            metaDataClass.addImport(packageRoot + "." + voPackage + "." + data.getName() + "Vo");

        }
        return myPackage;
    }


    public void writeTo(String path) {
        write(getBo(getTemplate("bo.$Bo")), path);
        write(getBoFactory(getTemplate("bo.$BoRepository")), path);
        write(getTypeSelf(getTemplate("bo.$TypeSelf")), path);
        write(getBe(getTemplate("entity.$Be")), path);
        write(getBeDao(getTemplate("dao.$BeDao")), path);
        write(getQuoteDao(getTemplate("dao.$QuoteDao")), path);
        write(getVo(getTemplate("vo.$Vo")), path);
        write(getQuote(getTemplate("entity.$QuoteBe")), path);
    }

    private static TemplateCompiler templateCompiler = new TemplateCompiler();

    private static Template getTemplate(String name) {
        try {

            InputStream inputStream = FileUtils.getClassPathResource("template/java/core/" + name.replace(".", "/") + ".java");
            Template compile = templateCompiler.compile(inputStream);
            inputStream.close();
            return compile;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static void write(MyPackage myPackage,String target) {
        myPackage.renderAndToFile(target);
    }

}
